#include <iostream>
using namespace std;
#include<unistd.h>
#include<string.h>
#include<ctype.h>
#include<fcntl.h>
#include<sys/types.h>
#include<sys/wait.h>
extern char** environ;
#define COMMAND_SIZE 126

#define NONE_DIR 0
#define INPUT_DIR 1
#define OUTPUT_DIR 2
#define APPEND_DIR 3
int dir = 0;
string filename;


#define MAX_ARGC 32
char* argv[MAX_ARGC];
int argc = 0;
int lastcode=0;
void makecommandline(char* cl,int size)
{
#define FORMPT "%s@wu-wang %s: #"
    snprintf(cl,size,FORMPT,getenv("USER"),getenv("PWD"));
}
void printCommandline()
{
    char prompt[COMMAND_SIZE];
    makecommandline(prompt,sizeof(prompt));
    printf("%s",prompt);
    fflush(stdout);
}

bool getCommandline(char* out,int size)
{
    char* c=fgets(out,size,stdin);
    if(c==nullptr) return false;
    out[strlen(out)-1]=0;
    if(strlen(out)==0) return false;
    return true;
}

bool commandPrase(char* commandline)
{
#define SEP " "
    argc=0;
    argv[argc++]=strtok(commandline,SEP);
    while(argv[argc++]=strtok(nullptr,SEP));
    argc--;
    return argc>0?true:false;
}

void TrimSpace(char* cmd,int& end)
{
    while(isspace(cmd[end]))
    {
        end++;
    }
}
void checkdir(char* cmd)
{
    dir=0;
    filename.clear();

    int begin=0;
    int end=strlen(cmd)-1;

    while(end>begin)
    {
        if(cmd[end]=='<')
        {
            cmd[end++]=0;
            TrimSpace(cmd,end);
            filename=cmd+end;
            dir=INPUT_DIR;
            break;
        }
        else if(cmd[end]=='>')
        {
            if(cmd[end-1]=='>')
            {
                cmd[end-1]=0;
                dir=APPEND_DIR;
            }
            else
            {
                dir=OUTPUT_DIR;
            }
            cmd[end++]=0;
            TrimSpace(cmd,end);
            filename=cmd+end;
            break;
        }
        else
        {
            end--;
        }
    }

}

bool Cd()
{
    // cd argc = 1
    if(argc == 1)
    {
        std::string home = getenv("HOME");
        if(home.empty()) return true;
        chdir(home.c_str());
    }
    else
    {
        std::string where = argv[1];
        // cd - / cd ~
        if(where == "-")
        {
            // Todu
        }
        else if(where == "~")
        {
            // Todu
        }
        else
        {
            chdir(where.c_str());
        }
    }
    return true;
}
bool Echo()
{
    if(argc == 2)
    {
          std::string opt = argv[1];
        if(opt == "$?")
        {
            std::cout << lastcode << std::endl;
            lastcode = 0;
        }
        else if(opt[0] == '$')
        {
            std::string env_name = opt.substr(1);
            const char *env_value = getenv(env_name.c_str());
            if(env_value)
                std::cout << env_value << std::endl;
        }
        else
        {
            std::cout << opt << std::endl;
        }
    }
    return true;
}
bool checkAndExcuBuiltin(char* argv[])
{
    string cmd = argv[0];
    if(cmd == "cd")
    {
        return Cd();    
    }
    else if(cmd == "echo")
    {
        
        return Echo();
    }
   
    return false;
}


int execute(char* argv[])
{
    pid_t id  = fork();
    if(id == 0)
    {
        int fd = -1;
        if(dir == INPUT_DIR)
        {
            fd=open(filename.c_str(),O_RDONLY);
            if (fd<0) exit(1);
            dup2(fd,0);
            close(fd);
        }
        else if(dir == OUTPUT_DIR)
        {
            fd=open(filename.c_str(),O_WRONLY|O_CREAT|O_TRUNC,0666);
            if(fd<0) exit(1);
            dup2(fd,1);
            close(fd);
        }
        else if(dir == APPEND_DIR)
        {
            fd=open(filename.c_str(),O_WRONLY|O_CREAT|O_APPEND,0666);
            if(fd<0) exit(1);
            dup2(fd,1);
            close(fd);
        }
        else{}
        execvpe(argv[0],argv,environ);
        exit(1);
    }
    int status =0;
    pid_t wid = waitpid(id,&status,0);
    if(wid>0)
    {
        lastcode = WEXITSTATUS(status);
    }
    return 0;
}




int main()
{
    while(true)
    {
       printCommandline();
       char commandline[COMMAND_SIZE];
       if(!getCommandline(commandline,sizeof(commandline))) continue;
       checkdir(commandline);
       if(!commandPrase(commandline)) continue;
    
       if(checkAndExcuBuiltin(argv)) continue;

       //printf("%s",filename.c_str());
       execute(argv);

    }


    return 0;
}
